package com.bestcem.xm.ticket.task;

import cn.hutool.core.lang.Validator;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.bestcem.xm.common.core.uitls.DateUtil;
import com.bestcem.xm.componet.redis.service.RedisService;
import com.bestcem.xm.survey.grpc.v1.services.Respondent;
import com.bestcem.xm.ticket.dao.AlertRecordDao;
import com.bestcem.xm.ticket.dao.RspdTimerDao;
import com.bestcem.xm.ticket.dao.TicketRuleDao;
import com.bestcem.xm.ticket.dao.dto.RspdTimerDTO;
import com.bestcem.xm.ticket.entity.mongo.Record;
import com.bestcem.xm.ticket.entity.mongo.RspdTimer;
import com.bestcem.xm.ticket.entity.mongo.TicketRule;
import com.bestcem.xm.ticket.enums.RespondentStatusEnum;
import com.bestcem.xm.ticket.enums.RspdTimerStatusEnum;
import com.bestcem.xm.ticket.grpc.client.TicketBaseSurveyGrpcService;
import com.bestcem.xm.ticket.grpc.client.TicketSurveyGrpcService;
import com.bestcem.xm.ticket.grpc.client.dto.survey.RespondentDTO;
import com.bestcem.xm.ticket.grpc.client.dto.survey.RspdTimerRespondent;
import com.bestcem.xm.ticket.mq.send.biz.TicketMessageSendService;
import com.bestcem.xm.ticket.service.dto.mq.FilterDTO;
import com.bestcem.xm.ticket.service.dto.ticket.rule.FilterEntityDTO;
import com.bestcem.xm.ticket.util.SurveyAnswerValidUtil;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;
import org.springframework.util.ObjectUtils;

import javax.annotation.Nullable;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.TimeUnit;

//import static com.bestcem.xm.ticket.mq.MqUtil.ALERT_RULE_TRIGGERED;

/**
 * 答卷状态条件检查定时任务
 *
 * @author gy.liu
 * @version 1.0
 * @date 2021/8/31 15:16
 **/
@Slf4j
@Component
public class RspdTimerTask {

    String resTian = "[\n" +
            "{\n" +
            "                    \"custom_qtype\": \"blank\",\n" +
            "                    \"gid\": 45,\n" +
            "                    \"_index\": \"Q7\",\n" +
            "                    \"answer\": [\n" +
            "                        {\n" +
            "                            \"blank\": \"2121\"\n" +
            "                        }\n" +
            "                    ],\n" +
            "                    \"qtype\": \"blank\",\n" +
            "                    \"ruleList\": [\n" +
            "                        \"6141bb254b118e7e2424d5a3\"\n" +
            "                    ],\n" +
            "                    \"title\": \"填空题\",\n" +
            "                    \"cid\": \"Q7\",\n" +
            "                    \"current_template\": {}\n" +
            "}\n" +
            "]";
    @Resource
    private RspdTimerDao rspdTimerDao;
    @Resource
    private TicketRuleDao ticketRuleDao;
    @Resource
    private AlertRecordDao alertRecordDao;
    //    @Resource
//    private MqUtil mqUtil;
    @Resource
    private TicketSurveyGrpcService ticketSurveyGrpcService;
    @Resource
    private TicketBaseSurveyGrpcService ticketBaseSurveyGrpcService;
    //    @Resource
//    private RabbitMqMessageSender rabbitMqMessageSender;
    @Resource
    private RedisService redisService;

    @Resource
    private TicketMessageSendService ticketMessageSendService;

//    @Autowired
//    private RabbitMqConstantConfig rabbitMqConstantConfig;

    /**
     * @author gy.liu
     * @date 2021/8/31 16:42
     */
    public void rspdStatusTimer() {
        if (log.isInfoEnabled()) {
            log.info("[Ticket] 进入 rspdStatusTimer·");
        }
        LocalDateTime localDateTime = DateUtil.getCurrentTime();
        long curTime = DateUtil.toSecond(localDateTime);
        long oldTime = curTime - 24 * 3600;
        List<RspdTimer> timerList = rspdTimerDao.findTimerByExpire(curTime, oldTime, RspdTimerStatusEnum.UNHANDLE.getIndex());
        if (CollectionUtils.isEmpty(timerList)) {
            if (log.isInfoEnabled()) {
                log.info("[Ticket] rspdStatusTimer timerList 为空");
            }
            return;
        }

        for (RspdTimer rspdTime : timerList) {
            String rspdTimeId = rspdTime.getId();
            // 获取锁
            RLock lock = this.redisService.getLock(getRspdTimerJobLockKey(rspdTimeId));
            if (lock.isLocked()) {
                if (log.isInfoEnabled()) {
                    log.info("[Ticket] rspdStatusTimer的id={}已在处理", rspdTimeId);
                }
                continue;
            }
            // 加锁成功与否
            boolean isLocked = false;
            try {
                // 加锁, 不自动释放
                if (lock.tryLock(0L, TimeUnit.SECONDS)) {
                    isLocked = true;
                    // 根据id查询rspdTimer状态
                    RspdTimer rspdTimer = rspdTimerDao.findById(rspdTimeId);
                    if (rspdTimer.getStatus() == RspdTimerStatusEnum.UNHANDLE.getIndex()) {
                        // 如果是待处理，更新状态为处理完成
                        if (handleRspdTimer(rspdTimer)) {
                            rspdTimerDao.updateTimerStatus(rspdTimeId, RspdTimerStatusEnum.FINISH.getIndex());
                        }
                    }
                } else { // 加锁失败
                    if (log.isInfoEnabled()) {
                        log.info("[Ticket] rspdStatusTimer的id={}已在处理", rspdTimeId);
                    }
                }
            } catch (InterruptedException e) {
                log.warn("[Ticket] rspdStatusTimer的id={}获取锁被中断", rspdTimeId, e);
            } catch (Exception e) {
                log.error("[Ticket]  rspdStatusTimer的id={}获取锁被中断", rspdTimeId, e);
            } finally {
                if (isLocked) {
                    // 是否当前线程持有锁
                    if (lock.isHeldByCurrentThread()) {
                        // 手动释放锁
                        lock.unlock();
                    } else {
                        log.error("[Ticket] rspdStatusTimer的id={} 的锁持有对象转移", rspdTimeId);
                    }
                }
            }
        }
    }

    public boolean handleRspdTimer(RspdTimer rspdTime) {
        RspdTimer.Search search = rspdTime.getSearch();
        if (Objects.isNull(search)) {
            return false;
        }
        List<String> ruleIds = rspdTime.getRuleIdList();
        if (CollectionUtils.isEmpty(ruleIds)) {
            return false;
        }

        List<TicketRule> ticketRuleList = new ArrayList<>();
        for (String ruleId : ruleIds) {
            TicketRule ticketRule = getRule(ruleId);
            if (Objects.nonNull(ticketRule)) {
                ticketRuleList.add(ticketRule);
            }
        }
        // 查询答卷信息
        Respondent.Builder builder = Respondent.newBuilder().setAgainDeliverRecordId(search.getAgainDeliverRecordId());
        List<RespondentDTO> respondentDTOS = ticketBaseSurveyGrpcService.listRespondent(builder.build(), null, null, null);
        if (log.isInfoEnabled()) {
            log.info("[Ticket] rspdStatusTimer listRespondent {}", JSONObject.toJSONString(respondentDTOS));
        }

        if (Objects.isNull(respondentDTOS)) {
            log.error("[Ticket] rspdStatusTimer listRespondent failed");
            return false;
        }

        RspdTimerRespondent rspd = new RspdTimerRespondent();
        if (CollectionUtils.isEmpty(respondentDTOS)) {
            rspd.setSearch(rspdTime.getSearch());
        } else {
            // 获取完成度最高且最近开始的问卷
            RespondentDTO respondentDTO = respondentDTOS.get(0);
            rspd = respondentDTOToRspdTimerRespondent(respondentDTO, null);
            for (int i = 1; i < respondentDTOS.size(); i++) {
                RespondentDTO respondentDTONew = respondentDTOS.get(i);
                if (respondentDTONew.getStatus() == RespondentStatusEnum.OPEN.getIndex()) {
                } else if (respondentDTONew.getStatus() == RespondentStatusEnum.BEGIN.getIndex()) {
                    if (rspd.getStatus() == RespondentStatusEnum.OPEN.getIndex()) {
                        rspd = respondentDTOToRspdTimerRespondent(respondentDTOS.get(i), null);
                    } else if (rspd.getStatus() == RespondentStatusEnum.BEGIN.getIndex()) {
                        if (respondentDTONew.getSeq() > rspd.getSeq()) {
                            rspd = respondentDTOToRspdTimerRespondent(respondentDTONew, null);
                        }
                    }
                } else {
                    rspd = respondentDTOToRspdTimerRespondent(respondentDTONew, null);
                    break;
                }
            }
        }
        Long seq = rspd.getSeq();
        // 根据seq查询答卷信息
        if (Objects.isNull(seq)) {
            return false;
        }

        RespondentDTO respondentDTO = ticketSurveyGrpcService.getRespondent(seq, true, false, false, "", true, "", null);// 待确认
        if (log.isInfoEnabled()) {
            log.info("[Ticket] rspdStatusTimer Respondent: {}", JSONObject.toJSONString(respondentDTO));
        }
        if (Validator.isNull(respondentDTO) || Validator.isEmpty(respondentDTO.getAnswers())) {
            log.error("[Ticket] 检查工单条件，没有获取到seq={}对应的答卷", seq);
        }
        rspd = respondentDTOToRspdTimerRespondent(respondentDTO, null);
        if (Objects.isNull(rspd)) {
            log.error("[Ticket] rspdStatusTimer rspd 为空");
            return false;
        }

        Integer status = rspd.getStatus();
        String answers = rspd.getAnswers();
        Map<String, List<Object>> recordData = new HashMap<>();
        Map<String, List<FilterEntityDTO>> trigedRules = new HashMap<>();
        if (CollectionUtils.isEmpty(respondentDTOS)) {
            return false;
        }

        for (TicketRule ticketRule : ticketRuleList) {
            List<JSONObject> filtersJsonList = ticketRule.getCondition().getFilters();
            if (CollectionUtils.isEmpty(filtersJsonList) || ObjectUtils.isEmpty(answers)) {
                log.error("[Ticket] filtersJsonList size = 0 or answers size = 0");
                return false;
            }
            // 预警条件检查
            JSONObject ansJson = (JSONObject) JSONObject.parse(answers);
            if (Objects.isNull(ansJson)) {
                log.error("[Ticket] ansJson is null");
                return false;
            }
            List<FilterEntityDTO> filterEntityDTOList = new ArrayList<>();
            for (JSONObject jsonObject : filtersJsonList) {
                filterEntityDTOList.add(JSON.toJavaObject(jsonObject, FilterEntityDTO.class));
            }

            for (FilterEntityDTO filter : filterEntityDTOList) {
                FilterDTO filterDTO = new FilterDTO();
                filterConvert(filter, filterDTO);
                try {
                    // filterDTO -> ticketRule.getCondition().getFilters() -> rspdTimerDao.findTimerByExpire(curTime, oldTime)
                    // ansJson -> 完成度最高且最近开始的问卷 RespondentDTO respondentDTO = respondentDTOS.get(0)
                    Map<String, Object> stringObjectMap = SurveyAnswerValidUtil.validTicketCondition(filterDTO, ansJson.getInnerMap(), status);
                    if (!CollectionUtils.isEmpty(stringObjectMap)) {
                        trigedRules.put(ticketRule.getId(), filterEntityDTOList);
                    }
                } catch (Exception e) {
                    log.error("[Ticket] ticket rspdStatusTimer validTicketCondition failed", e);
                }
            }
        }
        if (CollectionUtils.isEmpty(trigedRules)) {
            log.error("[Ticket] trigedRules size = 0");
            return false;
        }
        for (List<FilterEntityDTO> filters : trigedRules.values()) {
            if (Objects.nonNull(filters)) {
                List<Object> values = new ArrayList<>();
                String gid = null;
                for (FilterEntityDTO filter : filters) {
                    gid = filter.getId();
                    values.add(filter.getValue());
                }
                recordData.put(gid, values);
            }
        }
        List<String> ruleIdList = new ArrayList<>(trigedRules.keySet());
        Record record = new Record();
        record.setQProjectId(rspd.getProjectId());

        List<TicketRule.Condition> conditions = new ArrayList<>();
        trigedRules.values().forEach(filterEntityDTOSTemp -> {
            TicketRule.Condition condition = new TicketRule.Condition();
            List<JSONObject> list = new ArrayList<>();
            for (FilterEntityDTO filterEntityDTO : filterEntityDTOSTemp) {
                list.add((JSONObject) JSON.toJSON(filterEntityDTO));
            }
            condition.setFilters(list);
            conditions.add(condition);
        });

        record.setRuleList(conditions);
        record.setRspdSeq(seq);
        record.setData(JSONObject.parseObject(JSON.toJSONString(recordData)));
        record = alertRecordDao.saveTicketRecord(record);

        // 组装发送mq所需的数据
        RspdTimerDTO rspdTimerDTO = new RspdTimerDTO();
        rspdTimerDTO.setRuleIdList(ruleIdList);
        RspdTimerDTO.Rspd rspd1 = new RspdTimerDTO.Rspd();
        rspd1.setSeq(seq);
        rspd1.setStatus(status);
        rspd1.setAgainDeliverRecordId(rspd.getAgainDeliverRecordId());
        rspdTimerDTO.setRspd(rspd1);
        rspdTimerDTO.setRecordId(record.getId());

        // mq发送消息
        try {
            if (log.isInfoEnabled()) {
                log.info("[Ticket] rspdTimer mq send");
            }
//            rabbitMqMessageSender.sendMsg(rabbitMqConstantConfig.getAppBpDirectExchange(), rabbitMqConstantConfig.getAppBpQueue(), ALERT_RULE_TRIGGERED, rspdTimerDTO);
            ticketMessageSendService.ticketRuleTriggeredSend(rspdTimerDTO);
        } catch (Exception e) {
            log.error("[Ticket] ALERT_RULE_TRIGGERED MQ 消息发送失败", e);
        }
//        mqUtil.sendAppMq(ALERT_RULE_TRIGGERED, rspdTimerDTO);
//        ticketMessageService.ticketRuleTriggeredFanoutSend(rspdTimerDTO);
        // 暂时先简单考虑rule里只有一个答卷状态条件，所以处理后要么立刻触发，要么结束，不需要再次判断
        // 期间timer_expire被修改则不更新

        if (Objects.nonNull(rspdTime.getExpire())) {
            rspdTimerDao.updateTimer(rspdTime.getId(), rspdTime.getExpire());
        }
        return true;
    }

    @Nullable
    private RspdTimerRespondent respondentDTOToRspdTimerRespondent(RespondentDTO respondentDTO, RspdTimer.Search search) {
        if (Objects.isNull(respondentDTO)) {
            return null;
        }
        RspdTimerRespondent rspdTimerRespondent = new RspdTimerRespondent();
        rspdTimerRespondent.setSearch(search);
        rspdTimerRespondent.setId(respondentDTO.getId());
        rspdTimerRespondent.setAnswers(respondentDTO.getAnswers());
        rspdTimerRespondent.setProjectId(respondentDTO.getProjectId());
        rspdTimerRespondent.setDataStatus(respondentDTO.getDataStatus());
        rspdTimerRespondent.setStatus(respondentDTO.getStatus());
        rspdTimerRespondent.setPreDiscardStatus(respondentDTO.getPreDiscardStatus());
        rspdTimerRespondent.setSeq(respondentDTO.getSeq());
        rspdTimerRespondent.setParsed(respondentDTO.getParsed());
        rspdTimerRespondent.setVersion(respondentDTO.getVersion());
        rspdTimerRespondent.setSource(respondentDTO.getSource());
        rspdTimerRespondent.setGroupId(respondentDTO.getGroupId());
        rspdTimerRespondent.setGroupCode(respondentDTO.getGroupCode());
        rspdTimerRespondent.setPersonId(respondentDTO.getPersonId());
        rspdTimerRespondent.setUserAgent(respondentDTO.getUserAgent());
        rspdTimerRespondent.setClientType(respondentDTO.getClientType());
        rspdTimerRespondent.setIp(respondentDTO.getIp());
        rspdTimerRespondent.setBeginTime(respondentDTO.getBeginTime());
        rspdTimerRespondent.setFinishTime(respondentDTO.getFinishTime());
        rspdTimerRespondent.setRspdDataId(respondentDTO.getRspdDataId());
        rspdTimerRespondent.setRspdWeixinId(respondentDTO.getRspdWeixinId());
        rspdTimerRespondent.setRspdLocationId(respondentDTO.getRspdLocationId());
        rspdTimerRespondent.setRspdExtraId(respondentDTO.getRspdExtraId());
        rspdTimerRespondent.setRspdAttachmentId(respondentDTO.getRspdAttachmentId());
        rspdTimerRespondent.setExtSeq(respondentDTO.getExtSeq());
        rspdTimerRespondent.setSubmitSeq(respondentDTO.getSubmitSeq());
        rspdTimerRespondent.setIpCountry(respondentDTO.getIpCountry());
        rspdTimerRespondent.setIpProvince(respondentDTO.getIpProvince());
        rspdTimerRespondent.setIpCity(respondentDTO.getIpCity());
        rspdTimerRespondent.setRemark(respondentDTO.getRemark());
        rspdTimerRespondent.setMemberId(respondentDTO.getMemberId());
        rspdTimerRespondent.setCurrentLang(respondentDTO.getCurrentLang());
        rspdTimerRespondent.setDeliverId(respondentDTO.getDeliverId());
        rspdTimerRespondent.setDeliverGroupId(respondentDTO.getDeliverGroupId());
        rspdTimerRespondent.setAgainDeliverRecordId(respondentDTO.getAgainDeliverRecordId());
        rspdTimerRespondent.setQuotaCheckitemList(respondentDTO.getQuotaCheckitemList());
        rspdTimerRespondent.setCreatedDt(respondentDTO.getCreatedDt());
        rspdTimerRespondent.setExcelParsed(respondentDTO.getExcelParsed());
        rspdTimerRespondent.setSurveyGids(respondentDTO.getSurveyGids());
        rspdTimerRespondent.setWxInfo(respondentDTO.getWxInfo());
        rspdTimerRespondent.setDedCode(respondentDTO.getDedCode());
        rspdTimerRespondent.setIdySid(respondentDTO.getIdySid());
        rspdTimerRespondent.setScore(respondentDTO.getScore());
        rspdTimerRespondent.setExtra(respondentDTO.getExtra());
        rspdTimerRespondent.setMember(respondentDTO.getMember());
        rspdTimerRespondent.setMemberTags(respondentDTO.getMemberTags());
        rspdTimerRespondent.setExtParams(respondentDTO.getExtParams());
        rspdTimerRespondent.setCostTime(respondentDTO.getCostTime());
        rspdTimerRespondent.setRespondentStatus(respondentDTO.getRespondentStatus());
        rspdTimerRespondent.setQuotaCheckItems(respondentDTO.getQuotaCheckItems());
        rspdTimerRespondent.setCreateTime(respondentDTO.getCreateTime());
        rspdTimerRespondent.setEndTime(respondentDTO.getEndTime());
        rspdTimerRespondent.setStartTime(respondentDTO.getStartTime());
        rspdTimerRespondent.setAttachmentId(respondentDTO.getAttachmentId());
        rspdTimerRespondent.setBrowser(respondentDTO.getBrowser());
        rspdTimerRespondent.setComment(respondentDTO.getComment());
        rspdTimerRespondent.setDataId(respondentDTO.getDataId());
        rspdTimerRespondent.setDeliverChannel(respondentDTO.getDeliverChannel());
        rspdTimerRespondent.setDeliverCode(respondentDTO.getDeliverCode());
        rspdTimerRespondent.setDeliverSource(respondentDTO.getDeliverSource());
        rspdTimerRespondent.setExtraId(respondentDTO.getExtraId());
        rspdTimerRespondent.setGroup(respondentDTO.getGroup());
        rspdTimerRespondent.setIdySurveyUnionId(respondentDTO.getIdySurveyUnionId());
        rspdTimerRespondent.setLocationId(respondentDTO.getLocationId());
        rspdTimerRespondent.setMemberInfo(respondentDTO.getMemberInfo());
        rspdTimerRespondent.setMemberName(respondentDTO.getMemberName());
        rspdTimerRespondent.setOs(respondentDTO.getOs());
        rspdTimerRespondent.setUserId(respondentDTO.getUserId());
        rspdTimerRespondent.setWeixinId(respondentDTO.getWeixinId());
        rspdTimerRespondent.setWxUserInfo(respondentDTO.getWxUserInfo());
        return rspdTimerRespondent;
    }

    public TicketRule getRule(String ruleId) {
        TicketRule ticketRule = ticketRuleDao.findById(ruleId);
        if (Objects.isNull(ticketRule)) {
            log.error("TicketRule[id={}] not found", ruleId);
            return null;
        }
        return ticketRule;
    }

    public void filterConvert(FilterEntityDTO filter, FilterDTO filterDTO) {
        filterDTO.setCategory(filter.getCategory());
        filterDTO.setOperation(filter.getOperation());
        filterDTO.setSourceQ(JSON.toJSONString(filter.getSourceQ()));
        filterDTO.setValue(JSON.toJSONString(filter.getValue()));
    }

    /**
     * 获取锁的key
     *
     * @param id rspdTimerId
     * @return
     */
    public String getRspdTimerJobLockKey(String id) {
        return String.format("ticket:deliveragain:%s", id);
    }
}
